package org.example.framework.BeanDefinitionLoader;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.example.framework.BeanDefinition.BeanDefinition;
import org.example.framework.BeanDefinitionMap.BeanDefinitionMap;
import org.example.framework.BeanDefinitionMap.SimpleBeanDefinitionMap;
import org.example.framework.BeanException.BeanException;
import org.example.framework.BeanDefinition.BeanProperty;

import java.io.InputStream;

import static org.example.framework.BeanException.BeanException.ErrorType.*;

public class XmlBeanDefinitionLoader implements BeanDefinitionLoader{
    private final BeanDefinitionMap beanDefinitionMap;

    @Override
    public BeanDefinitionMap getMap() {
        return beanDefinitionMap;
    }

    public XmlBeanDefinitionLoader() {
        beanDefinitionMap = new SimpleBeanDefinitionMap();
    }

    public Document getDocument(String path) throws BeanException {
        try(InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(path)) {
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            return document;
        }
        catch (Exception e){
            throw new BeanException(FILE_NOTFOUND, "file not found");
        }
    }

    public void getRoot(Document document) throws BeanException{
        Element element = document.getRootElement();
        if(element.getName().trim().equals("beans")) {
            for(Element bElement: element.elements()){
                getBeanDefinition(bElement);
            }
        }
        else{
            throw new BeanException(CONTENT_ERR, "wrong content in the config file");
        }
    }

    public void getBeanDefinition(Element element) throws BeanException{
        if(!element.getName().equals("bean")){
            throw new BeanException(CONTENT_ERR, "wrong bean element");
        }

        try{
            String id = element.attributeValue("id");
            String clazz = element.attributeValue("class");

            BeanDefinition beanDefinition = new BeanDefinition(id, Class.forName(clazz));

            for(Element pElement: element.elements("property")){
                String name = pElement.attributeValue("name");
                String ref = pElement.attributeValue("ref");

                beanDefinition.addProperty(new BeanProperty(name, ref));
            }
            beanDefinitionMap.addBeanDefinition(id, beanDefinition);
        }
        catch (ClassNotFoundException e){
            throw new BeanException(CLASS_NOTFOUND, "class not find");
        }
    }

    public void run(String path) throws BeanException {
        getRoot(getDocument(path));
    }
}
